use serde::{Serialize, Deserialize};
use std::process::Command;
use std::net::IpAddr;
use std::env;
use log::{error, info};
use reqwest;
use local_ip_address as local_ip;
use tauri::command;

#[derive(Debug, Serialize)]
pub struct SystemInfo {
    hostname: String,
    os_info: OsInfo,
    network: NetworkInfo,
}

#[derive(Debug, Serialize)]
pub struct OsInfo {
    name: String,
    version: String,
}

#[derive(Debug, Serialize)]
pub struct NetworkInfo {
    ip_addresses: String,
    external_ip: Option<String>,
    dns_servers: Vec<String>,
    wifi_name: String,
}

#[derive(Debug, Serialize)]
pub struct WireguardInterface {
    pub name: String,
    pub status: String,
    pub address: String,
}

// System Information Functions
fn get_hostname() -> String {
    match env::var("HOSTNAME") {
        Ok(hostname) => hostname,
        Err(_) => {
            if let Ok(output) = Command::new("hostname").output() {
                String::from_utf8_lossy(&output.stdout).trim().to_string()
            } else {
                "Unknown".to_string()
            }
        }
    }
}

fn get_os_info() -> OsInfo {
    let os = os_info::get();
    OsInfo {
        name: os.os_type().to_string(),
        version: os.version().to_string(),
    }
}

// Network Functions
fn get_ip_addresses() -> String {
    local_ip::local_ip()
        .map(|ip| ip.to_string())
        .unwrap_or_else(|_| "Unable to get IP".to_string())
}

fn get_external_ip() -> Option<String> {
    info!("Getting external IP address");
    
    match reqwest::blocking::get("https://api.ipify.org") {
        Ok(response) => response.text().ok(),
        Err(_) => {
            match reqwest::blocking::get("https://ifconfig.me") {
                Ok(response) => response.text().ok(),
                Err(e) => {
                    error!("Failed to get external IP: {}", e);
                    None
                }
            }
        }
    }
}

fn get_dns_info() -> Vec<String> {
    let mut dns_servers = Vec::new();
    if let Ok(output) = Command::new("cat").arg("/etc/resolv.conf").output() {
        let content = String::from_utf8_lossy(&output.stdout);
        for line in content.lines() {
            if line.starts_with("nameserver") {
                if let Some(server) = line.split_whitespace().nth(1) {
                    dns_servers.push(server.to_string());
                }
            }
        }
    }
    dns_servers
}

fn get_wifi_name() -> String {
    #[cfg(target_os = "macos")]
    {
        if let Ok(output) = Command::new("networksetup")
            .args(["-getairportnetwork", "en0"])
            .output()
        {
            let wifi_info = String::from_utf8_lossy(&output.stdout);
            if let Some(ssid) = wifi_info.split("Current Wi-Fi Network: ").nth(1) {
                return ssid.trim().to_string();
            }
        }
    }
    "Unknown".to_string()
}

fn get_wireguard_interfaces() -> Result<Vec<WireguardInterface>, String> {
    let mut interfaces = Vec::new();
    
    #[cfg(target_os = "macos")]
    {
        if let Ok(output) = Command::new("wg")
            .args([ "show", "interfaces"])
            .output() 
        {
            if !output.status.success() {
                return Err("Administrator privileges required".to_string());
            }

            let interfaces_str = String::from_utf8_lossy(&output.stdout);
            for name in interfaces_str.lines() {
                if let Ok(show_output) = Command::new("wg")
                    .args(["show", name])
                    .output() 
                {
                    let info = String::from_utf8_lossy(&show_output.stdout);
                    let address = info.lines()
                        .find(|line| line.contains("interface:"))
                        .and_then(|line| line.split(':').nth(1))
                        .unwrap_or("unknown")
                        .trim()
                        .to_string();
                        
                    interfaces.push(WireguardInterface {
                        name: name.to_string(),
                        status: "active".to_string(),
                        address,
                    });
                }
            }
        }
    }

    if interfaces.is_empty() {
        Err("No WireGuard interfaces found or insufficient permissions".to_string())
    } else {
        Ok(interfaces)
    }
}

// Tauri Commands
#[command]
pub fn cmd_get_system_info() -> SystemInfo {
    SystemInfo {
        hostname: get_hostname(),
        os_info: get_os_info(),
        network: NetworkInfo {
            ip_addresses: get_ip_addresses(),
            external_ip: get_external_ip(),
            dns_servers: get_dns_info(),
            wifi_name: get_wifi_name(),
        }
    }
}

#[command]
pub fn cmd_get_wireguard_interfaces() -> Result<Vec<WireguardInterface>, String> {
    get_wireguard_interfaces()
}
